from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory, jsonify
from werkzeug.utils import secure_filename
from pptx import Presentation
from sparkai.llm.llm import ChatSparkLLM, ChunkPrintHandler
from sparkai.core.messages import ChatMessage
from docx import Document
import os
import threading
import time
import hashlib
import hmac
import base64
import json
import requests
import webbrowser

# SparkAI配置
SPARKAI_URL = 'wss://spark-api.xf-yun.com/v3.5/chat'
SPARKAI_APP_ID = ''  # 替换为你的AI
SPARKAI_API_SECRET = ''  # 替换为你的AS
SPARKAI_API_KEY = ''  # 替换为你的AK
SPARKAI_DOMAIN = 'generalv3.5'

app = Flask(__name__)
app.secret_key = 'supersecretkey'
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['PROCESSED_FOLDER'] = 'processed'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 限制文件大小为16MB

if not os.path.exists(app.config['UPLOAD_FOLDER']):
    os.makedirs(app.config['UPLOAD_FOLDER'])
if not os.path.exists(app.config['PROCESSED_FOLDER']):
    os.makedirs(app.config['PROCESSED_FOLDER'])

spark = ChatSparkLLM(
    spark_api_url=SPARKAI_URL,
    spark_app_id=SPARKAI_APP_ID,
    spark_api_key=SPARKAI_API_KEY,
    spark_api_secret=SPARKAI_API_SECRET,
    spark_llm_domain=SPARKAI_DOMAIN,
    streaming=False,
)
handler = ChunkPrintHandler()

APPId = ""  # 替换为你的应用ID
APISecret = ""  # 替换为你的秘钥
current_task = None


class AIPPT:
    def __init__(self, APPId, APISecret, Text, Theme, Author):
        self.APPid = APPId
        self.APISecret = APISecret
        self.text = Text
        self.theme = Theme
        self.author = Author
        self.header = {}
        self.log = []  # 将日志设置为实例变量
        self.ppt_url = None

    def get_signature(self, ts):
        try:
            auth = self.md5(self.APPid + str(ts))
            return self.hmac_sha1_encrypt(auth, self.APISecret)
        except Exception as e:
            self.log.append(str(e))
            return None

    def hmac_sha1_encrypt(self, encrypt_text, encrypt_key):
        return base64.b64encode(
            hmac.new(encrypt_key.encode('utf-8'), encrypt_text.encode('utf-8'), hashlib.sha1).digest()).decode(
            'utf-8')

    def md5(self, text):
        return hashlib.md5(text.encode('utf-8')).hexdigest()

    def create_task(self):
        url = 'https://zwapi.xfyun.cn/api/aippt/create'
        timestamp = int(time.time())
        signature = self.get_signature(timestamp)
        body = self.getbody(self.text, self.theme, self.author)

        headers = {
            "appId": self.APPid,
            "timestamp": str(timestamp),
            "signature": signature,
            "Content-Type": "application/json; charset=utf-8"
        }
        self.header = headers
        response = requests.request("POST", url=url, data=json.dumps(body), headers=headers).text
        resp = json.loads(response)
        if resp['code'] == 0:
            return resp['data']['sid']
        else:
            self.log.append('创建PPT任务失败')
            return None

    def getbody(self, text, theme, author):
        body = {
            "query": text,
            "create_model": "auto",
            "theme": theme,
            "business_id": "",
            "author": author,
            "is_card_note": False
        }
        return body

    def get_process(self, sid):
        self.log.append("sid: " + sid)
        if sid is not None:
            response_text = requests.request("GET", url=f"https://zwapi.xfyun.cn/api/aippt/progress?sid={sid}",
                                             headers=self.header).text
            response = json.loads(response_text)
            return response
        else:
            return None

    def get_result(self):
        task_id = self.create_task()
        if task_id is not None:
            while True:
                response = self.get_process(task_id)
                if response is not None:
                    if 'data' in response and 'process' in response['data']:
                        process = response['data']['process']
                        self.log.append(f"任务进度: {process}%")
                        if process == 100:
                            self.ppt_url = response['data']['pptUrl']
                            self.log.append(f"PPT 生成完成: {self.ppt_url}")
                            break
                    else:
                        self.log.append("未收到有效响应或响应结构不正确，将在一段时间后重试...")
                        time.sleep(5)
                else:
                    self.log.append("未收到有效响应，将在一段时间后重试...")
                    time.sleep(5)
                    continue

                if response is not None and 'data' in response and 'sid' in response['data']:
                    task_id = response['data']['sid']
                else:
                    self.log.append("无法获取最新的任务进度，将在一段时间后重试...")
                    time.sleep(5)
                    continue
        else:
            self.log.append("创建任务失败，无法获取task_id")
            return None

        return self.ppt_url, self.log


def extract_outline_from_ppt(ppt_path):
    prs = Presentation(ppt_path)
    outline = []
    for slide in prs.slides:
        for shape in slide.shapes:
            if hasattr(shape, "text"):
                outline.append(shape.text)
    return '\n'.join(outline)


def save_outline_to_docx(outline, filename):
    doc = Document()
    doc.add_heading('PPT大纲', 0)
    for line in outline.split('\n'):
        doc.add_paragraph(line)
    doc_path = os.path.join(app.config['PROCESSED_FOLDER'], filename)
    doc.save(doc_path)
    return doc_path


@app.route('/')
def home():
    return render_template('home.html')


@app.route('/index')
def index():
    return render_template('index.html')


@app.route('/upload', methods=['POST'])
def upload():
    if 'file' not in request.files:
        flash('没有上传文件部分')
        return redirect(url_for('index'))

    file = request.files['file']
    if file.filename == '':
        flash('没有选择文件')
        return redirect(url_for('index'))

    if file and file.filename.endswith('.pptx'):
        filename = secure_filename(file.filename)
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        file.save(file_path)

        ppt_outline = extract_outline_from_ppt(file_path)

        messages = [ChatMessage(
            role="user", content=ppt_outline
        )]

        handler = ChunkPrintHandler()
        response = spark.generate([messages], callbacks=[handler]).generations[0][0].text

        docx_filename = filename.rsplit('.', 1)[0] + '.docx'
        docx_path = save_outline_to_docx(response, docx_filename)

        return render_template('result.html', outline=response, docx_path=docx_filename)

    flash('无效的文件格式')
    return redirect(url_for('index'))


@app.route('/download/<filename>')
def download_file(filename):
    return send_from_directory(app.config['PROCESSED_FOLDER'], filename, as_attachment=True)


@app.route('/generate_ppt', methods=['POST'])
def generate_ppt_route():
    global current_task
    outline_content = request.form['outline_content']
    theme = request.form['theme']
    author = request.form['author']
    current_task = AIPPT(APPId, APISecret, outline_content, theme, author)
    threading.Thread(target=current_task.get_result).start()
    return redirect(url_for('task_log'))


@app.route('/generate_outline', methods=['GET', 'POST'])
def generate_outline():
    if request.method == 'POST':
        article_content = request.form['article_content']

        # 构造用户消息
        user_message = ChatMessage(role="user", content=f"请为以下文章生成一个大纲：{article_content}")

        # 生成回复消息
        reply = spark.generate([[user_message]], callbacks=[handler]).generations[0][0].text

        return render_template('outline_result.html', outline=reply)
    return render_template('generate_outline.html')


@app.route('/task_log')
def task_log():
    return render_template('task_log.html')


@app.route('/check_status')
def check_status():
    global current_task
    if current_task:
        if current_task.ppt_url:
            return jsonify({'status': 'done', 'ppt_url': current_task.ppt_url})
        return jsonify({'status': 'running', 'log': current_task.log})
    return jsonify({'status': 'no_task'})


@app.route('/ppt_result')
def ppt_result():
    ppt_url = request.args.get('purl')
    return render_template('ppt_result.html', ppt_url=ppt_url)


@app.route('/outline_result')
def outline_result():
    return render_template('outline_result.html')


@app.route('/previous_index')
def previous_index():
    return render_template('previous_index.html')


def open_browser():
    webbrowser.open_new('http://127.0.0.1:5000/')


if __name__ == '__main__':
    threading.Timer(1, open_browser).start()
    # app.run(debug=True)
    app.run(host='0.0.0.0', port=5000)

